/*
 *  main.c
 *  
 *
 *  Created by Philip Asare on 12/6/10.
 *  Copyright 2010. All rights reserved.
 *
 *
 * monome sketch-it base station 
 *
 * communication
 * -------------
 * to controllers --> wireless (RT-Link)
 * to console display --> UART
 *
 */


#include <nrk.h>
#include <include.h>
#include <ulib.h>
#include <stdio.h>
#include <avr/sleep.h>
#include <hal.h>
#include <rt_link.h>
#include <nrk_error.h>

/* controller tx slots --> base station rx slots */
#define C1_TX 2
#define C2_TX 4
#define C3_TX 6
#define C4_TX 8

/* controller rx slots --> base station rx slots */
#define ALL_RX 3
#define C1_RX 5
#define C2_RX 7
#define C3_RX 9
#define C4_RX 11

/* game states and controller tracking */
#define MAX_NUM_PLAYERS 4
#define MAX_NUM_OF_PATTERNS 4

uint8_t state, num_players;
uint8_t player_tx[MAX_NUM_PLAYERS];
uint8_t player_rx[MAX_NUM_PLAYERS];

#define SYNC 0
#define SELECT (1<<1)
#define PREGAME (1<<2)

/* monome helper functions */

#define type(x) (sizeof(x) + PKT_DATA_START)

typedef struct{
	uint8_t player;
} monome_comm_sync_pkt;

typedef struct{
	uint8_t players;
	uint8_t game_type;
} monome_comm_select_pkt;

typedef struct{
  uint8_t pattern_no;
} monome_pattern_selected;

monome_pattern_selected pattern;
monome_comm_sync_pkt sync_pkt;

uint8_t tx_len;

/* task setup */

NRK_STK Stack1[NRK_APP_STACKSIZE];
nrk_task_type TaskOne;
void Task1(void);

inline void monome_comm_init();
inline void monome_setup_system();
inline void monome_add_controller(uint8_t slot);
inline void monome_select_pattern();
void nrk_create_taskset();

uint8_t tx_buf[RF_MAX_PAYLOAD_SIZE];
uint8_t rx_buf[RF_MAX_PAYLOAD_SIZE];

int
main ()
{
	uint16_t div;
	nrk_setup_ports();
	nrk_setup_uart(UART_BAUDRATE_115K2);
	
	printf( "Starting up...\r\n" );
	
	
	nrk_init();
	
	nrk_led_clr(0);
	nrk_led_clr(1);
	nrk_led_clr(2);
	nrk_led_clr(3);
	
	nrk_time_set(0,0);
	
	
	rtl_task_config();
	
	nrk_create_taskset ();
	
	nrk_start();
	
	return 0;
}

void Task1()
{
	//uint8_t j, i;
	uint8_t *local_rx_buf;
	uint8_t length,slot;
	int8_t rssi;
	
	monome_comm_init();
	monome_setup_system();
	while(!rtl_ready())  nrk_wait_until_next_period(); 
	
	
	
	while(1){
	        printf ( "base station\r\n" );
		if( rtl_rx_pkt_check()!=0 )
		{
			nrk_led_set(BLUE_LED);
			local_rx_buf=rtl_rx_pkt_get(&length, &rssi, &slot);
			printf( "Got Packet on slot %d %d: \r\n",slot,length );
			if(length == type(monome_comm_sync_pkt)){
				rtl_rx_pkt_release();
				if((state & SYNC) && (num_players < MAX_NUM_PLAYERS)){
					monome_add_controller(slot);
				}
				else{
					printf("Maximum number of players synced\r\n");
				}
			}
			if(length == type(monome_comm_select_pkt)){
			  
			}
			nrk_led_clr(BLUE_LED);
		}

		nrk_wait_until_next_period();

	}
	
}


void
nrk_create_taskset()
{
	
	
	TaskOne.task = Task1;
	TaskOne.Ptos = (void *) &Stack1[NRK_APP_STACKSIZE-1];
	TaskOne.Pbos = (void *) &Stack1[0];
	TaskOne.prio = 2;
	TaskOne.FirstActivation = TRUE;
	TaskOne.Type = BASIC_TASK;
	TaskOne.SchType = PREEMPTIVE;
	TaskOne.period.secs = 1;
	TaskOne.period.nano_secs = 0;
	TaskOne.cpu_reserve.secs = 0;
	TaskOne.cpu_reserve.nano_secs = 100*NANOS_PER_MS;
	TaskOne.offset.secs = 0;
	TaskOne.offset.nano_secs= 0;
	nrk_activate_task (&TaskOne);
	
	
	printf ("Create done\r\n");
}

inline void monome_comm_init(){
	rtl_init (RTL_COORDINATOR);
	
	/* rx schedules */
	rtl_set_schedule( RTL_RX, C1_TX, 1 );
	rtl_set_schedule( RTL_RX, C2_TX, 1 );
	rtl_set_schedule( RTL_RX, C3_TX, 1 );
	rtl_set_schedule( RTL_RX, C4_TX, 1 );
	
	/* tx schedules */
	rtl_set_schedule( RTL_TX, ALL_RX, 1 );
	rtl_set_schedule( RTL_TX, C1_RX, 1 );
	rtl_set_schedule( RTL_TX, C2_RX, 1 );
	rtl_set_schedule( RTL_TX, C3_RX, 1 );
	rtl_set_schedule( RTL_TX, C4_RX, 1 );
	
	rtl_start();
	rtl_rx_pkt_set_buffer(rx_buf, RF_MAX_PAYLOAD_SIZE);
}

inline void monome_setup_system(){
	int i;
	state = SYNC;
	num_players = 0;
	for(i = 0; i < MAX_NUM_PLAYERS; i++){
		player_rx[i] = -1;
		player_tx[i] = -1;
	}
	
}

inline void monome_add_controller(uint8_t slot){
	int i, already_player;
	already_player = 0;
	for(i = 0; i<num_players; i++){
		if(slot == player_tx[i]){
			already_player = 1;
		}
	}
	if(already_player == 0){
		/* consider code to add player back if player is lost */
		switch(slot){
			case C1_TX: player_tx[num_players] = C1_TX; 
				player_rx[num_players] = C1_RX; 
				break;
			case C2_TX: player_tx[num_players] = C2_TX; 
				player_rx[num_players] = C2_RX; 
				break;
			case C3_TX: player_tx[num_players] = C3_TX; 
				player_rx[num_players] = C3_RX; 
				break;
			case C4_TX: player_tx[num_players] = C4_TX; 
				player_rx[num_players] = C4_RX; 
				break;
			default: break;
		}
		while( rtl_tx_pkt_check(player_rx[num_players])!=0 );
		sync_pkt.player = num_players;
		printf("player number sent: %d\r\n", sync_pkt.player);
		memcpy(&tx_buf[PKT_DATA_START], &sync_pkt, sizeof(monome_comm_sync_pkt));
		tx_len = type(monome_comm_sync_pkt);
		rtl_tx_pkt( tx_buf, tx_len, player_rx[num_players]);
		rtl_wait_until_tx_done(player_rx[num_players]);
		num_players++; 
		printf("Synched new player: player %d\r\n", num_players);
	}
	
}

inline void monome_select_pattern()
{
  uint8_t i;
  pattern.pattern_no = rand() % MAX_NUM_OF_PATTERNS;
  memcpy( &tx_buf[PKT_DATA_START], &pattern, sizeof( monome_pattern_selected ) );
  tx_len = type( monome_pattern_selected );
  for ( i = 0; i < num_players; i++ ){
    rtl_tx_pkt( tx_buf, tx_len, player_rx[i] );
    rtl_wait_until_tx_done( player_rx[i] );
  }
  printf( "Pattern Selected: %d", pattern.pattern_no );
}
